package main

import (
	"bufio"
	"bytes"
	"crypto/hmac"
	"crypto/md5"
	"crypto/sha1"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"peilian-api/app/global/variable"
	_ "peilian-api/bootstrap"
	"peilian-api/utils/sdk"
	"strconv"
	"sync"
	"time"

	"github.com/go-redis/redis"
	"golang.org/x/net/websocket"
)

var allFiles []string

var HOST = "rtasr.xfyun.cn/v1/ws"

var APPID = "c01ca6f9"
var APPKEY = "def21fdfa59f4353c061b7041084cdaa"

// 结束标识

var END_TAG = "{\"end\": true}"

// 每次发送的数据大小

var SLICE_SIZE = 1280
var wg sync.WaitGroup

var workers = 1
var endTag int

// var filePath = "/Users/a123/Desktop/go/peilian-api/scripts/test_xunfei/2.pcm"

var filePath = "https://3dcreator.cn-wlcb.ufileos.com/peilian/static/video/2023-02-09/81540_1273_1_no_question.pcm"

// var filePath = "https://metagc-cdn.aminer.cn/peilian/static/video/2023-02-09/81540_1273_1_no_question.pcm"

func main() {
	// wg.Add(workers)
	// for i := 0; i < workers; i++ {
	// 	go StartConn(i)
	// 	fmt.Println(i)
	// }
	// wg.Wait()
	// fmt.Println("----------一下是计算------------")
	// 屏蔽掉的id
	var bp = []int{11, 12, 13, 76, 77, 78}

	fmt.Println("----")
	sc := variable.DB.Redis.ZRange("test_10001", 0, -1)
	s, _ := sc.Result()
	var wordCount = 0
	// 记录时间
	var wrs []WsRecord
	for i := 0; i < len(s); i++ {
		var winfo WsInfo
		json.Unmarshal([]byte(s[i]), &winfo)
		var b = []rune(winfo.Word)
		for j := 0; j < len(b); j++ {
			wordCount += 1
			for k := 0; k < len(bp); k++ {
				if bp[k]+1 == wordCount {
					f, _ := strconv.ParseFloat(winfo.Bg, 64)
					wr := WsRecord{}
					wrs = append(wrs, WsRecord{Begin: (winfo.Wb*10+f)/40 - 1, End: (winfo.We*10+f)/40 + 1})
					wr.Begin = winfo.Wb
				}
			}
		}
	}

	// 读取语音
	data := make([]byte, SLICE_SIZE)
	resp, err := http.Get(filePath)
	reader := bufio.NewReaderSize(resp.Body, 1280*32)
	defer resp.Body.Close()
	if err != nil {
		return
	}

	var count = 0
	var audioBuffer = new(bytes.Buffer)
	for i, e := reader.Read(data); i > 0; i, e = reader.Read(data) {
		if e != nil {
			if e.Error() == "EOF" {
				// 读到结束符
				break
			}
			fmt.Println("read file error: " + e.Error())
			return
		}
		count++
		for _, v := range wrs {
			if count >= int(v.Begin) && count <= int(v.End) {
				fmt.Println("-----------")
				data = make([]byte, 1280)
				fmt.Println(fmt.Sprintf("begin:%f, end:%f", v.Begin, v.End))
				break
			}
		}
		// 将音频写入新文件
		audioBuffer.Write(data[:i])
		// time.Sleep(40 * time.Millisecond)
	}

	// 将音频写入pcm 文件
	sdk.IOput(audioBuffer.Bytes(), "peilian_local/test/bb.pcm", "application/octet-stream")

}

func StartConn(workerCode int) {
	t1 := time.Now()
	ts := strconv.FormatInt(time.Now().Unix(), 10)
	mac := hmac.New(sha1.New, []byte(APPKEY))
	strByte := []byte(APPID + ts)
	strMd5Byte := md5.Sum(strByte)
	strMd5 := fmt.Sprintf("%x", strMd5Byte)
	mac.Write([]byte(strMd5))
	signa := url.QueryEscape(base64.StdEncoding.EncodeToString(mac.Sum(nil)))
	requestParam := "appid=" + APPID + "&ts=" + ts + "&signa=" + signa + "&lang=cn"
	conn, err := websocket.Dial("wss://"+HOST+"?"+requestParam, websocket.SupportedProtocolVersion, "http://"+HOST)
	if err != nil {
		fmt.Println(err)
		return
	}
	var message string
	websocket.Message.Receive(conn, &message)
	var m map[string]string
	err = json.Unmarshal([]byte(message), &m)
	if err != nil {
		println(err.Error())
		return
	} else if m["code"] != "0" {
		fmt.Println("handshake fail!" + message)
		return
	}
	defer conn.Close()
	sendChan := make(chan int, 1)

	readChan := make(chan string, 1)
	defer close(sendChan)
	defer close(readChan)
	//fmt.Println("文件路径: " + filePath)
	go send(conn, sendChan, filePath)
	go receive(conn, readChan, workerCode)
	<-sendChan
	<-readChan
	//fmt.Println(text)
	wg.Done()
	t2 := time.Now()
	fmt.Println(fmt.Sprintf("[%d]一共用了： ", workerCode), t2.Unix()-t1.Unix())
}

func send(conn *websocket.Conn, sendChan chan int, filePath string) {
	// 分片上传音频
	defer func() {
		sendChan <- 1
	}()
	data := make([]byte, SLICE_SIZE)
	resp, err := http.Get(filePath)
	defer resp.Body.Close()
	reader := bufio.NewReaderSize(resp.Body, 1280*128)
	// audio, err := os.Open(filePath)
	// defer audio.Close()
	if err != nil {
		fmt.Println("open file error: " + err.Error())
	}
	var count = 0
	var audioBuffer = new(bytes.Buffer)
	for i, e := reader.Read(data); i > 0; i, e = reader.Read(data) {
		if e != nil {
			if e.Error() == "EOF" {
				// 读到结束符
				break
			}
			fmt.Println("read file error: " + e.Error())
			return
		}
		count++
		if count >= 60 && count <= 72 {
			fmt.Println("---")
			// data = make([]byte, 1280)
		}

		audioBuffer.Write(data[:i])

		if err := websocket.Message.Send(conn, data[:i]); err != nil {
			fmt.Println("send byte msg err: ", err)
			return
		}
		// println("send data success, sleep 40 ms")
		time.Sleep(40 * time.Millisecond)
	}

	// 将音频写入pcm 文件
	sdk.IOput(audioBuffer.Bytes(), "peilian_local/test/aa.pcm", "application/octet-stream")

	// 上传结束符
	if err := websocket.Message.Send(conn, END_TAG); err != nil {
	} else {
		println("send end tag success, ", len(END_TAG))
	}
}

func receive(conn *websocket.Conn, readChan chan string, workerCode int) {
	text := ""
	for {
		var msg []byte
		var result map[string]string
		if err := websocket.Message.Receive(conn, &msg); err != nil {
			if err.Error() == "EOF" {
				fmt.Println("receive data end --", time.Now().Unix())
			} else {
				fmt.Println("receive msg error: ", err.Error())
			}

			break
		}

		err := json.Unmarshal(msg, &result)
		if err != nil {
			println(string(msg))
			fmt.Println("response json parse error")
			continue
		}

		if result["code"] == "0" {
			var asrResult AsrResult
			err := json.Unmarshal([]byte(result["data"]), &asrResult)
			if err != nil {
				println("receive msg: ", string(msg))

				break
			}
			var wsText = WsText{}
			if asrResult.Cn.St.Type == "0" {
				fmt.Printf("%+v\n", asrResult.Cn.St.Bg)
				//println("------------------------------------------------------------------------------------------------------------------------------------")
				for _, wse := range asrResult.Cn.St.Rt[0].Ws {
					// fmt.Printf("%+v", wse)
					var winfo WsInfo
					winfo.Bg = asrResult.Cn.St.Bg
					winfo.Wb = wse.Wb
					var t = ""
					for _, cwe := range wse.Cw {
						// fmt.Println(cwe.W)
						text += cwe.W

						t += cwe.W
					}
					winfo.Word = t
					winfo.We = wse.We
					winfo.Wb = wse.Wb
					winfo.Ed = asrResult.Cn.St.Ed
					// 写入

					fmt.Println(winfo)
					// b, _ := json.Marshal(winfo)
					// bg, _ := strconv.ParseFloat(winfo.Bg, 64)
					wsText.Wi = append(wsText.Wi, winfo)
				}

				b, _ := json.Marshal(wsText) // 写出去
				// 模拟写入redis
				var wt = WsText{}
				json.Unmarshal(b, &wt)

				// 写入redis
				for i := 0; i < len(wt.Wi); i++ {
					bg, _ := strconv.ParseFloat(wt.Wi[i].Bg, 64)
					wb := wt.Wi[i].Wb
					b, _ := json.Marshal(wt.Wi[i])
					variable.DB.Redis.ZAdd("test_10001", redis.Z{Member: string(b), Score: bg + wb*10})
				}

				fmt.Printf("%+v\n", asrResult.Cn.St.Ed)
				//println("\r\n------------------------------------------------------------------------------------------------------------------------------------")
			}
			if asrResult.Ls {
				endTag += 1
				fmt.Println(fmt.Sprintf("[%d]收到结束标志 ", workerCode), endTag, "  ", time.Now().Unix())
			}

		} else {
			println("invalid result: ", string(msg))
		}
	}
	fmt.Println(text)
	readChan <- text
}

type AsrResult struct {
	Cn    Cn      `json:"cn"`
	SegId float64 `json:"seg_id"`
	Ls    bool    `json:"ls"`
}

type Cn struct {
	St St `json:"st"`
}

type St struct {
	Bg   string      `json:"bg"`
	Ed   string      `json:"ed"`
	Type string      `json:"type"`
	Rt   []RtElement `json:"rt"`
}

type RtElement struct {
	Ws []WsElement `json:"ws"`
}

type WsElement struct {
	Wb float64     `json:"wb"`
	We float64     `json:"we"`
	Cw []CwElement `json:"cw"`
}

type CwElement struct {
	W  string `json:"w"`
	Wp string `json:"wp"`
}

type WsInfo struct {
	Bg   string  `json:"bg"`
	Ed   string  `json:"ed"`
	Wb   float64 `json:"wb"`
	We   float64 `json:"we"`
	Word string  `json:"word"`
}

type WsText struct {
	Bg   string `json:"bg"`
	Ed   string `json:"ed"`
	Wi   []WsInfo
	Text string `json:"text"`
}

// 记录时间
type WsRecord struct {
	Begin float64 `json:"begin"`
	End   float64 `json:"end"`
}
